<script setup lang="ts">
/**
 * 配合 el-table 列插槽实现单个字段可编辑
 * 通过插槽自己实现显示和输入框
 */
import { ref, reactive, watch, nextTick } from 'vue'
import type { PropType } from 'vue'
import { Edit as IconEdit, Check as IconCheck, Close as IconClose } from '@element-plus/icons-vue'
import { onClickOutside } from '@vueuse/core'

const props = defineProps({
	/** 设置一个提交事件，返回Promise，then时自动触发emit change，finally时自动关闭loading */
	submitMethod: {
		type: Function as PropType<() => Promise<any>>,
		required: true,
	},
	/** 按钮尺寸 */
	size: {
		type: String as PropType<'small' | 'default' | 'large'>,
		default: 'default',
	},
	/** 是否激活编辑状态
	 * 默认undefined，此时由组件自己控制
	 * 当设置此值，组件变为受控状态，完全由props.onoff决定是否激活编辑状态
	 * 支持v-model，如果想单向控制就是用:onoff，双向控制用v-model:onoff
	 */
	onoff: {
		type: Boolean,
		default: undefined,
	},
})

const isEditMode = ref(false)
const isLoading = ref(false)

const editDivRef = ref()

const emit = defineEmits(['change', 'update:onoff'])

onClickOutside(editDivRef, () => toggleOnoff(false))

const openEditMode = () => {
	isEditMode.value = true
}
const closeEditMode = () => {
	isEditMode.value = false
}
const toggleOnoff = (onoff: boolean) => {
	if (typeof props.onoff == 'undefined') {
		if (onoff) openEditMode()
		else closeEditMode()
	} else {
		emit('update:onoff', onoff)
	}
}
const onClickSubmit = () => {
	isLoading.value = true
	props
		.submitMethod()
		.then(() => {
			emit('change')
			toggleOnoff(false)
		})
		.finally(() => (isLoading.value = false))
}
watch(
	() => props.onoff,
	(val) => {
		if (typeof val !== 'undefined') {
			if (val) openEditMode()
			else closeEditMode()
		}
	},
	{ immediate: true }
)
</script>
<template>
	<div>
		<div v-if="!isEditMode" class="flex items-center space-x-2">
			<slot></slot>
			<el-button type="default" :size="props.size" :icon="IconEdit" @click="toggleOnoff(true)"></el-button>
		</div>
		<div
			v-else
			class="flex items-center"
			ref="editDivRef"
			@keyup.enter="onClickSubmit"
			@keyup.esc="toggleOnoff(false)"
		>
			<slot name="input" :loading="isLoading"></slot>
			<el-button-group class="ml-2" :size="props.size">
				<el-button type="primary" :icon="IconCheck" :loading="isLoading" @click.stop="onClickSubmit" />
				<el-button :icon="IconClose" @click="toggleOnoff(false)" />
			</el-button-group>
		</div>
	</div>
</template>
